//*********************************************************
//
//    Copyright (c) Microsoft. All rights reserved.
//    This code is licensed under the Apache License, Version 2.0.
//    THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
//    ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
//    IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
//    PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//*********************************************************

using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Drawing;
using System.Runtime.Serialization;

namespace Microsoft.Research.DataLayer
{
    partial class DataProduct
    {
        public Image ContentsAsImage
        {
            get
            {
                if ((0 != this.Type.ToLower().CompareTo("image/gif"))
                    && (0 != this.Type.ToLower().CompareTo("image/jpg"))
                    && (0 != this.Type.ToLower().CompareTo("image/bmp"))
                    && (0 != this.Type.ToLower().CompareTo("image/png")))
                {
                    throw new ArgumentException("You cannot call ContentAsImage if the content is not an image object");
                }

                Image img = ToImage(this.Contents);

                return img;
            }

            set
            {
                if ((0 != this.Type.ToLower().CompareTo("image/gif"))
                    && (0 != this.Type.ToLower().CompareTo("image/jpg"))
                    && (0 != this.Type.ToLower().CompareTo("image/bmp"))
                    && (0 != this.Type.ToLower().CompareTo("image/png")))
                {
                    throw new ArgumentException("You cannot call ContentAsImage if the content is not an image object");
                }

                byte[] __cnv = DataProduct.FromImage(value);

                CreateBinidngForContent(__cnv);

                this.Contents = __cnv;
            }
        }

        public string ContentsAsString
        {
            set
            {
                if ((0 != this.Type.ToLower().CompareTo("text/richtext")) &&
                    (0 != this.Type.ToLower().CompareTo("text/plain")) &&
                    (0 != this.Type.ToLower().CompareTo("text/html")) &&
                    (0 != this.Type.ToLower().CompareTo("text/xml")))
                {
                    throw new ArgumentException("You cannot call ContentAsImage if the content is not an text object");
                }

                byte[] __cnv = UnicodeEncoding.Unicode.GetBytes(value);

                CreateBinidngForContent(__cnv);

                this.Contents = __cnv;
            }

            get
            {
                if ((0 != this.Type.ToLower().CompareTo("text/richtext")) &&
                   (0 != this.Type.ToLower().CompareTo("text/plain")) &&
                   (0 != this.Type.ToLower().CompareTo("text/html")) &&
                   (0 != this.Type.ToLower().CompareTo("text/xml")))
                {
                    throw new ArgumentException("You cannot call ContentAsImage if the content is not an text object");
                }

                string str = UnicodeEncoding.Unicode.GetString(this.Contents);

                return str;
            }
        }

        public string ContentsAsBase64String
        {
            set
            {
                byte[] __cnv = Convert.FromBase64String(value);

                CreateBinidngForContent(__cnv);

                this.Contents = __cnv;
            }

            get
            {
                string str = Convert.ToBase64String(this.Contents);
                return str;
            }
        }

        public byte[] ContentAsByteArray
        {
            get
            {
                return this.Contents;
            }
            set
            {
                byte[] __cnv = value;

                CreateBinidngForContent(__cnv);

                this.Contents = __cnv;
            }
        }

        /// <summary>
        /// Gets a value indicating whether this instance is final.
        /// </summary>
        /// <value><c>true</c> if this instance is final; otherwise, <c>false</c>.</value>
        public bool IsFinal
        {
            get
            {
                if (this.CreatorParameter == null)
                    return false;
                else if (this.CreatorParameter.IsFinal)
                {
                    return true;
                }
                return false;
            }
        }

        #region Helper Conversion "From" methods
        public static byte[] FromImage(Image src)
        {

            System.IO.MemoryStream saveStore = new System.IO.MemoryStream();
            src.Save(saveStore, System.Drawing.Imaging.ImageFormat.Png);
            byte[] __cnv_contents = saveStore.GetBuffer();
            return __cnv_contents;
        }

        public static byte[] FromStream(Stream src)
        {
            System.IO.MemoryStream saveStore = new System.IO.MemoryStream();
            BinaryReader sr = new BinaryReader(src);

            byte[] buffer;

            do
            {
                buffer = sr.ReadBytes(16384);
                if (buffer != null)
                    saveStore.Write(buffer, 0, buffer.Length);
            } while (buffer != null && buffer.Length > 0);

            byte[] __cnv_contents = saveStore.GetBuffer();
            return __cnv_contents;
        }

        public static byte[] FromObject(object src)
        {
            System.Runtime.Serialization.Formatters.Binary.BinaryFormatter bf =
                new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
            MemoryStream srcOut = new MemoryStream();

            bf.Serialize(srcOut, src);

            return srcOut.GetBuffer();
        }
        #endregion

        #region Conversion "To" methods
        public static Image ToImage(byte[] src)
        {
            MemoryStream ms = new MemoryStream(src);
            Image img = Image.FromStream(ms);
            return img;
        }
        #endregion

        //public class CopyHelper
        //{
        //    public CopyHelper(ActivityInstance intance)
        //    {
        //        this.intance = intance;
        //    }

        //    public IObject CopyTo(Connection target, DataProduct product)
        //    {
        //        Connection store = target;
        //        List<Parameter> mydata = new List<Parameter>();
        //        mydata.Add(new Parameter("Type", Parameter.ParamType.String, Parameter.ParamDirection.In, product.type));
        //        mydata.Add(new Parameter("PreviewSize", Parameter.ParamType.Int, Parameter.ParamDirection.In, product.previewsize));
        //        mydata.Add(new Parameter("ContentsSize", Parameter.ParamType.Int, Parameter.ParamDirection.In, product.contentssize));
        //        mydata.Add(new Parameter("ActivityTypeName", Parameter.ParamType.String, Parameter.ParamDirection.In, product.activitytypename));
        //        mydata.Add(new Parameter("ActivityLabel", Parameter.ParamType.String, Parameter.ParamDirection.In, product.activitylabel));
        //        mydata.Add(new Parameter("ProducedByID", Parameter.ParamType.Guid, Parameter.ParamDirection.In,
        //            (this.intance == null ? Guid.Empty : ((IObject)this.intance).ID)));
        //        PipelineParameter<DataProduct> pipe = new PipelineParameter<DataProduct>(CreateFromDataStore);
        //        IObject newObj = product.SaveTo(mydata, store, pipe);
        //        product.SavePreviewBlob(store);
        //        product.SaveContentsBlob(store);
        //        return newObj;
        //    }

        //    ActivityInstance intance;
        //}

        /// <summary>
        /// Creates the content binidng based on the Data Product settings.
        /// </summary>
        /// <param name="__cnv">The __CNV.</param>
        private void CreateBinidngForContent(byte[] __cnv)
        {
            DataproductGlobalSetting setting = null;
            try
            {
                GlobalSetting globalSetting = null;
                try
                {
                    globalSetting = GlobalSetting.LoadAll(this.Conn)[0];
                }
                catch (RecordNotFoundException)
                {
                }

                if (null != globalSetting)
                    setting = DataProductGlobalSettingService.GetSettings(globalSetting.Dataproduct);
            }
            catch (Exception)
            {
                // Ignore: This is because the setting might not be configured. 
                //  If the setting is not configured then we will not create any bindingds.
            }

            int size = GetFileSize(__cnv.Length);
            if (setting != null && size >= setting.MinimumSize)
            {
                if (size > setting.MaximumSize)
                {
                    throw new DataProviderException("Size of Contents is more than the specified maximum in the global setting file.");
                }
                else
                {
                    try
                    {
                        DataReferenceStore store = DataReferenceStore.Load(setting.DatastoreID, this.Conn);
                        this.Bindings.Add(IBindable.Fields.Contents, store);
                    }
                    catch (Exception)
                    {
                        // Ignore: This is because the Data store might not be configured at all. 
                        //  If there are no data stores then we should use our own registry for storign the Data.
                    }
                }
            }
        }

        /// <summary>
        /// Gets the size of the file.
        /// </summary>
        /// <param name="byteCount">The byte count.</param>
        /// <returns></returns>
        private int GetFileSize(int byteCount)
        {
            return byteCount / 1024;
        }

        public void ContentsCopy(Stream target)
        {
            List<IBlob> list = new List<IBlob>();
            foreach (DataProductContentsBlob blob in this.ContentsStores)
            {
                list.Add(blob);
            }

            // Copy contents using target stream parameter
            BlobBase.FetchBlobs<DataProductContentsBlob, List<IBlob>>(list, ref target);
        }

        public void ContentsDownload(string toFile)
        {
            Stream f = File.OpenWrite(toFile);
            ContentsCopy(f);
            f.Close();           
        }

        /// <summary>
        /// Deletes the preview and content blobs associated with this DataProduct.
        /// </summary>
        public void DeleteBlobs()
        {
            // Delete preview blobs.
            foreach (DataProductPreviewBlob previewBlob in this.PreviewStores)
            {
                previewBlob.Delete();
            }
            // Delete content blobs.
            foreach (DataProductContentsBlob contentBlob in this.ContentsStores)
            {
                contentBlob.Delete();
            }
            this.PreviewStores.Refresh();
            this.ContentsStores.Refresh();
        }
    }
}
